// Copyright 2019 Google LLC.
#include "modules/skparagraph/include/TypefaceFontProvider.h"
#include <algorithm>
#include "include/core/SkFontMgr.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "src/core/SkFontDescriptor.h"
#include "modules/skparagraph/include/FontCollection.h"

#include <native_drawing/drawing_register_font.h>

namespace skia {
namespace textlayout {

int TypefaceFontProvider::onCountFamilies() const { return fRegisteredFamilies.count(); }

void TypefaceFontProvider::onGetFamilyName(int index, SkString* familyName) const {
    SkASSERT(index < fRegisteredFamilies.count());
    familyName->set(fFamilyNames[index]);
}

sk_sp<SkFontStyleSet> TypefaceFontProvider::onMatchFamily(const char familyName[]) const {
    auto found = fRegisteredFamilies.find(SkString(familyName));
    if (found) {
      return *found;
    }
    return nullptr;
}

size_t TypefaceFontProvider::registerTypeface(sk_sp<SkTypeface> typeface) {
     if (typeface == nullptr) {
         return 0;
     }

     SkString familyName;
     typeface->getFamilyName(&familyName);

     return registerTypeface(std::move(typeface), std::move(familyName));
}

size_t TypefaceFontProvider::registerFontData(sk_sp<SkTypeface> typeface, const SkString& familyName) {
    if (FontCacheMgr::getInstance().isExist(familyName)) {
        return 0;
    }

    auto data = typeface->getData();
    uint8_t* fontBuffer = const_cast<uint8_t*>(data->bytes());
    size_t length = data->size();
    uint32_t ret = OH_Drawing_RegisterFontBuffer(*fFontCollection, familyName.c_str(), fontBuffer, length);
    
    const char* resultMsg = nullptr;
    switch (ret) {
        case 0:
            resultMsg = "Success";
            break;
        case 6:
            resultMsg = "Buffer size is zero";
            break;
        case 7:
            resultMsg = "Font collection is empty";
            break;
        case 9:
            resultMsg = "Corrupted font file";
            break;
        default:
            resultMsg = "Unknown error";
            break;
    }

    SkDebugf("OH_Drawing_RegisterFontBuffer returned %u (%s) for font family: %s\n",
             ret, resultMsg, familyName.c_str());

    // The font data will be released to save memory
    typeface->clearData();
    if (ret == 0) {
        FontCacheMgr::getInstance().addFont(familyName);
    }
    return ret;
}

size_t TypefaceFontProvider::registerTypeface(sk_sp<SkTypeface> typeface, const SkString& familyName) {
     if (familyName.size() == 0) {
         return 0;
     }
    
    if (typeface->getData()) {
        if (fFontCollection) {
            auto ret = registerFontData(typeface, familyName);
            if (ret != 0) {
                return 0;
            }
        } else {
            fPendingTypefaces.push_back({familyName, typeface});
        }
    } else {
        SkDebugf("TypefaceFontProvider::registerTypeface invalid typeface!\n");
        return 0;
    }

     auto found = fRegisteredFamilies.find(familyName);
     if (found == nullptr) {
         found = fRegisteredFamilies.set(familyName, sk_make_sp<TypefaceFontStyleSet>(familyName));
         fFamilyNames.emplace_back(familyName);
     }

     (*found)->appendTypeface(std::move(typeface));

     return 1;
}

void TypefaceFontProvider::setFontCollection(FontCollection *fontCollection) {
    fFontCollection = fontCollection;
    for (auto &pair : fPendingTypefaces) {
        registerFontData(pair.second, pair.first);
    }
    fPendingTypefaces.clear();
}

TypefaceFontStyleSet::TypefaceFontStyleSet(const SkString& familyName)
        : fFamilyName(familyName) {}

int TypefaceFontStyleSet::count() { return fStyles.size(); }

void TypefaceFontStyleSet::getStyle(int index, SkFontStyle* style, SkString* name) {
     SkASSERT(index < fStyles.size());
     if (style) {
         *style = fStyles[index]->fontStyle();
     }
     if (name) {
         *name = fFamilyName;
     }
}

sk_sp<SkTypeface> TypefaceFontStyleSet::createTypeface(int index) {
    SkASSERT(index < fStyles.size());
    return fStyles[index];
}

sk_sp<SkTypeface> TypefaceFontStyleSet::matchStyle(const SkFontStyle& pattern) {
     return this->matchStyleCSS3(pattern);
}

void TypefaceFontStyleSet::appendTypeface(sk_sp<SkTypeface> typeface) {
    if (typeface.get() != nullptr) {
        fStyles.emplace_back(std::move(typeface));
    }
}

}  // namespace textlayout
}  // namespace skia
